#include <Game/Include/ServerLogic.h>

#include <Game/Include/TimeGameEvent.h>

ServerLogic::ServerLogic(Channel* comm_channel, SyncQueue* output_queue, int time_step_ms)
    :DistributionLogic(comm_channel, output_queue)
{
    this->time_step_ms = time_step_ms;
    this->ordering_queue = new SyncQueue();
    this->output_task = new Task(output_task_function, this, T_TaskPriority::TASK_PRIORITY_HIGH, TASK_SLEEP_TIME_NULL);
    this->output_task->start();
    this->clock_task = new Task(clock_task_function, this, T_TaskPriority::TASK_PRIORITY_CRITICAL, this->time_step_ms);
    // it will start later
    // in server side what i get from channel i put on the ordering queue
    ChannelReceiverTaskData* receiver_data = new ChannelReceiverTaskData();
    receiver_data->channel = this->comm_channel;
    receiver_data->output_queue = this->ordering_queue;
    this->channel_receiver_task = new Task(channel_receiver_task_function, receiver_data, T_TaskPriority::TASK_PRIORITY_NORMAL, TASK_SLEEP_TIME_NULL);
    receiver_data->channel_receiver_task = channel_receiver_task;
    this->channel_receiver_task->start();
}


ServerLogic::~ServerLogic(void)
{
    this->ordering_queue->closeAndDiscardAll();
    delete this->ordering_queue;
}

void ServerLogic::processGameEvent(GameEvent* game_event)
{
    SimpleMessage* simple_message = new SimpleMessage(game_event);
    this->ordering_queue->push(simple_message);
}

void ServerLogic::startClock()
{
    this->clock_task->start();
}

void ServerLogic::stopClock()
{
    this->clock_task->stop();
}

void ServerLogic::output_task_function(void* user_data)
{
    ServerLogic* server_logic = reinterpret_cast<ServerLogic*>(user_data);
    SimpleMessage* simple_message = NULL;
    try
    {
        // get the event ordered
        simple_message = server_logic->ordering_queue->pop();
        // send it to client
        server_logic->comm_channel->send(simple_message->clonar());
        // push it to local process
        server_logic->output_queue->push(simple_message);
    }
    catch (SyncQueue::SyncQueueExceptionType e)
    {
        server_logic->output_task->stop(); 
    }
    catch (ChannelExceptionType e)
    {
        delete simple_message;
        server_logic->output_task->stop();
    }    
}

void ServerLogic::clock_task_function(void* user_data)
{
    ServerLogic* server_logic = reinterpret_cast<ServerLogic*>(user_data);
    GameEvent* game_event = new TimeGameEvent(server_logic->time_step_ms);
    SimpleMessage* simple_message = new SimpleMessage(game_event);
    server_logic->ordering_queue->push(simple_message);
    delete game_event;
}
